package m.html.list;

import com.alibaba.fastjson.JSONArray;
import m.common.model.util.QueryCondition;
import m.html.element.*;
import m.html.element.other.DisplayItem;
import m.html.element.other.IElement;
import m.html.element.other.InputElement;
import m.system.util.DateUtil;
import m.system.util.ObjectUtil;
import m.system.util.StringUtil;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class ListSearch {

	private final boolean isField;
	private final String title;
	private final String field;
	private final SearchType type;
	private InputElement element;
	private List<DisplayItem> disItems;
	private String dictType;
	private boolean dictTree=false;
	
	private ListSearch(boolean isField,String title,String field,SearchType type,List<DisplayItem> disItems) {
		this.isField=isField;
		this.title=title;
		this.field=field;
		this.type=type;
		this.disItems=disItems;
	}
	/**
	 * 自定义查询条件, 不会根据field去过滤列表, 需要在构建result时自行添加查询条件
	 */
	public static ListSearch custom(String title,String field) {
		return custom(title,field,SearchType.STR_EQ);
	}
	/**
	 * 自定义查询条件, 不会根据field去过滤列表, 需要在构建result时自行添加查询条件
	 */
	public static ListSearch custom(String title,String field,SearchType type) {
		return custom(title,field,type, new ArrayList<>());
	}
	/**
	 * 自定义查询条件, 不会根据field去过滤列表, 需要在构建result时自行添加查询条件
	 */
	public static ListSearch custom(String title,String field,List<DisplayItem> disItems) {
		return custom(title,field,SearchType.STR_EQ,disItems);
	}
	/**
	 * 自定义查询条件, 不会根据field去过滤列表, 需要在构建result时自行添加查询条件
	 */
	public static ListSearch custom(String title,String field,SearchType type,List<DisplayItem> disItems) {
		return new ListSearch(false,title,field,type,disItems);
	}
	/**
	 * field查询条件, 会根据field去过滤列表
	 */
	public static ListSearch field(String title,String field) {
		return field(title,field,SearchType.STR_EQ);
	}
	/**
	 * field查询条件, 会根据field去过滤列表
	 */
	public static ListSearch field(String title,String field,SearchType type) {
		return field(title,field,type, new ArrayList<>());
	}
	/**
	 * field查询条件, 会根据field去过滤列表
	 */
	public static ListSearch field(String title,String field,List<DisplayItem> disItems) {
		return field(title,field,SearchType.STR_EQ,disItems);
	}
	/**
	 * field查询条件, 会根据field去过滤列表
	 */
	public static ListSearch field(String title,String field,SearchType type,List<DisplayItem> disItems) {
		return new ListSearch(true,title,field,type,disItems);
	}
	public ListSearch setElement(InputElement element) {
		this.element=element;
		return this;
	}
	public boolean isField() {
		return isField;
	}
	public String getTitle() {
		return title;
	}
	public String getField() {
		return field;
	}
	public SearchType getType() {
		return type;
	}
	public ListSearch addDisItem(DisplayItem item) {
		this.disItems.add(item);
		return this;
	}
	public ListSearch addDisItem(String value,String title) {
		this.disItems.add(DisplayItem.value(value, title));
		return this;
	}
	public ListSearch setDisItems(List<DisplayItem> list) {
		this.disItems=list;
		return this;
	}
	public ListSearch setDictType(String dictType) {
		this.dictType = dictType;
		return this;
	}
	public ListSearch setDictTree(boolean dictTree){
		this.dictTree=dictTree;
		return this;
	}
	public String getDictType() {
		return dictType;
	}
	public List<DisplayItem> getDisItems(){
		return this.disItems;
	}
	public Object[] toCondition(String realField,Map<String,String> params) {
		StringBuilder cond=new StringBuilder();
		List<Object> ps= new ArrayList<>();
		if(this.type.toString().contains("RANGE")) {
			if(null!=params.get(this.field+"_down")) {
				String valueDown=String.valueOf(params.get(this.field+"_down"));
				if(!StringUtil.isSpace(valueDown)) {
					cond.append(realField).append(">=?");
					if(this.type==SearchType.NUMBER_RANGE||this.type==SearchType.HIDDEN_NUMBER_RANGE) 
						ps.add(Double.parseDouble(valueDown));
					else if(this.type==SearchType.DATE_RANGE||this.type==SearchType.HIDDEN_DATE_RANGE) 
						ps.add(DateUtil.getStartDay((Date) ObjectUtil.convert(Date.class, valueDown)));
					else if(this.type==SearchType.DATETIME_RANGE||this.type==SearchType.HIDDEN_DATETIME_RANGE) 
						ps.add(ObjectUtil.convert(Date.class, valueDown));
				}
			}
			if(null!=params.get(this.field+"_up")) {
				String valueUp=String.valueOf(params.get(this.field+"_up"));
				if(!StringUtil.isSpace(valueUp)) {
					if(cond.length()>0) cond.append(" and ");
					cond.append(realField).append("<=?");
					if(this.type==SearchType.NUMBER_RANGE||this.type==SearchType.HIDDEN_NUMBER_RANGE) 
						ps.add(Double.parseDouble(valueUp));
					else if(this.type==SearchType.DATE_RANGE||this.type==SearchType.HIDDEN_DATE_RANGE) 
						ps.add(DateUtil.getEndDay((Date) ObjectUtil.convert(Date.class, valueUp)));
					else if(this.type==SearchType.DATETIME_RANGE||this.type==SearchType.HIDDEN_DATETIME_RANGE) 
						ps.add(ObjectUtil.convert(Date.class, valueUp));
				}
			}
		}else {
			if(null!=params.get(this.field)) {
				String value=String.valueOf(params.get(this.field));
				if(!StringUtil.isSpace(value)) {
					if(value.matches("^\\[.*\\]$")) {
						JSONArray arr=JSONArray.parseArray(value);
						if(arr.size()>0) {
							cond.append("(1=2 ");
							for (Object o : arr) {
								cond.append(" or ").append(realField).append("=?");
								ps.add(o);
							}
							cond.append(")");
						}
					}else if(this.type==SearchType.STR_MANY_LIKE||this.type==SearchType.HIDDEN_MANY_LIKE) {
						String[] arr=value.split("\\s+");
						cond.append("(1=2 ");
						for (String s : arr) {
							cond.append(" or instr(").append(realField).append(",?)>0");
							ps.add(s);
						}
						cond.append(")");
					}else if(this.type==SearchType.STR_LIKE||this.type==SearchType.HIDDEN_LIKE) {
						cond.append("instr(").append(realField).append(",?)>0");
						ps.add(value);
					}else {
						cond.append(realField).append("=?");
						ps.add(value);
					}
				}
			}
		}
		return new Object[] {cond.toString(),ps};
	}
	public List<QueryCondition> toCondition(Map<String,String> params){
		List<QueryCondition> cons= new ArrayList<>();
		if(this.type.toString().contains("RANGE")) {
			if(null!=params.get(this.field+"_down")) {
				String valueDown=String.valueOf(params.get(this.field+"_down"));
				if(!StringUtil.isSpace(valueDown)) {
					if(this.type==SearchType.NUMBER_RANGE||this.type==SearchType.HIDDEN_NUMBER_RANGE) 
						cons.add(QueryCondition.ge(this.field, Double.parseDouble(valueDown)));
					else if(this.type==SearchType.DATE_RANGE||this.type==SearchType.HIDDEN_DATE_RANGE) 
						cons.add(QueryCondition.ge(this.field, DateUtil.getStartDay((Date) ObjectUtil.convert(Date.class, valueDown))));
					else if(this.type==SearchType.DATETIME_RANGE||this.type==SearchType.HIDDEN_DATETIME_RANGE) 
						cons.add(QueryCondition.ge(this.field, ObjectUtil.convert(Date.class, valueDown)));
				}
			}
			if(null!=params.get(this.field+"_up")) {
				String valueUp=String.valueOf(params.get(this.field+"_up"));
				if(!StringUtil.isSpace(valueUp)) {
					if(this.type==SearchType.NUMBER_RANGE||this.type==SearchType.HIDDEN_NUMBER_RANGE) 
						cons.add(QueryCondition.le(this.field, Double.parseDouble(valueUp)));
					else if(this.type==SearchType.DATE_RANGE||this.type==SearchType.HIDDEN_DATE_RANGE) 
						cons.add(QueryCondition.le(this.field, DateUtil.getEndDay((Date) ObjectUtil.convert(Date.class, valueUp))));
					else if(this.type==SearchType.DATETIME_RANGE||this.type==SearchType.HIDDEN_DATETIME_RANGE) 
						cons.add(QueryCondition.le(this.field, ObjectUtil.convert(Date.class, valueUp)));
				}
			}
		}else {
			if(null!=params.get(this.field)) {
				String value=String.valueOf(params.get(this.field));
				if(!StringUtil.isSpace(value)) {
					if(value.matches("^\\[.*\\]$")){
						JSONArray arr=JSONArray.parseArray(value);
						if(arr.size()>0) {
							QueryCondition[] qc=new QueryCondition[arr.size()];
							for(int i=0;i<qc.length;i++) {
								qc[i]=QueryCondition.eq(this.field, arr.get(i));
							}
							cons.add(QueryCondition.or(qc));
						}
					}else if(this.type==SearchType.STR_MANY_LIKE||this.type==SearchType.HIDDEN_MANY_LIKE) {
						String[] arr=value.split("\\s+");
						QueryCondition[] qc=new QueryCondition[arr.length];
						for(int i=0;i<arr.length;i++) {
							qc[i]=QueryCondition.like(this.field, arr[i]);
						}
						cons.add(QueryCondition.or(qc));
					}else if(this.type==SearchType.STR_LIKE||this.type==SearchType.HIDDEN_LIKE) {
						cons.add(QueryCondition.like(this.field, value));
					}else {
						cons.add(QueryCondition.eq(this.field, value));
					}
				}
			}
		}
		return cons;
	}
	public Element toElement() {//输出组件
		if(this.type.toString().indexOf("HIDDEN")==0) {
			return null;
		}else if(null!=this.element) {
			this.element.setField("inputParams['"+this.field+"']");
			return this.element;
		}else if(!StringUtil.isSpace(this.dictType)) {
			if(this.dictTree){
				return Element.tag("div").A("style","padding:0 0 10px;")
					.E(Element.tag("a-tree-select").A("v-model:value","inputParams['"+this.field+"']")
						.A(":tree-data","dictTreeOptions('"+this.dictType+"')").A("multiple")
						.A(":filterTreeNode","treeSelectFilter").A("style","width:230px;").A(":showArrow","true")
						.A(":getPopupContainer", "selectPopup")
					);
			}else{
				return Element.tag("div").A("style","padding:0 0 10px;")
					.E(Element.tag("a-select").A("v-model:value","inputParams['"+this.field+"']")
						.A(":options","dictOptions('"+this.dictType+"')").A("mode","multiple")
						.A(":filter-option","selectFilter").A("style","width:230px;").A(":showArrow","true")
						.A(":getPopupContainer", "selectPopup")
					);
			}
		}else if(this.disItems.size()>10) {
			List<IElement> rs= new ArrayList<>();
			for(DisplayItem di : this.disItems) {
				rs.add(
					Element.tag("a-select-option").A("key",di.getValue()).A("value",di.getValue()).E(new Text(di.getTitle()))
				);
			}
			return Element.tag("a-select").A("v-model:value","inputParams['"+this.field+"']").A("mode","multiple")
				.A(":filter-option","selectFilter").A("style","width:100%;").A(":showArrow","true")
				.E(rs);
		}else if(this.disItems.size()>0){
			List<IElement> rs= new ArrayList<>();
			for(DisplayItem di : this.disItems) {
				rs.add(
					Element.tag("span").A("style","padding:5px 10px 5px 0px;min-width:120px;display:inline-block;")
					.E(Element.tag("a-checkbox").A("value",di.getValue()).E(new Text(di.getTitle())))
				);
			}
			return Element.tag("a-checkbox-group").A("v-model:value","inputParams['"+this.field+"']")
					.E(rs);
		}else if(this.type==SearchType.STR_EQ||this.type==SearchType.STR_LIKE||this.type==SearchType.STR_MANY_LIKE){//字符串类型
			return new Input("inputParams['"+this.field+"']");
		}else if(this.type==SearchType.NUMBER_RANGE) {//数字类型
			return new Row()
				.addCol(new InputNumber("inputParams['"+this.field+"_down']").setExtend("style=\"width:100%\""), 11)
				.addCol(new Text("<div style=\"text-align:center;\">~</div>"), 2)
				.addCol(new InputNumber("inputParams['"+this.field+"_up']").setExtend("style=\"width:100%\""), 11);
		}else if(this.type==SearchType.DATE_RANGE||this.type==SearchType.DATETIME_RANGE) {
			boolean flag=this.type==SearchType.DATETIME_RANGE;
			return new Row()
				.addCol(new DatePicker("inputParams['"+this.field+"_down']",flag).setExtend("style=\"width:100%\""), 11)
				.addCol(new Text("<div style=\"text-align:center;\">~</div>"), 2)
				.addCol(new DatePicker("inputParams['"+this.field+"_up']",flag).setExtend("style=\"width:100%\""), 11);
		}
		return null;
	}
	public String outField() {
		if(this.type==SearchType.NUMBER_RANGE||this.type==SearchType.HIDDEN_NUMBER_RANGE
				||this.type==SearchType.DATE_RANGE||this.type==SearchType.HIDDEN_DATE_RANGE
				||this.type==SearchType.DATETIME_RANGE||this.type==SearchType.HIDDEN_DATETIME_RANGE) {
			return "'"+this.field+"_down':'','"+this.field+"_up':'',";
		}
		return "'"+this.field+"':'',";
	}
	@Override
	public String toString() {
		Element ele=toElement();
		return null==ele?"":ele.toString();
	}
}
